package com.chuangke.lowcode.config;

import com.chuangke.common.annotation.Entity;
import com.chuangke.lowcode.EntityModelConstants;
import com.chuangke.lowcode.model.EntityModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class EntityModelRegister implements EnvironmentAware {

    private static final Logger log = LoggerFactory.getLogger(EntityModelRegister.class);

    static final String DEFAULT_RESOURCE_PATTERN = "*.class";

    @Override
    public void setEnvironment(Environment environment) {
        log.info("=================扫描自定义注解开始======================");

        // 扫描指定包，可以手动传入
        String basePackages = "com.chuangke.**.entity";

        List<Class<?>> candidates = scanPackages(basePackages);

        if (candidates.isEmpty()) {
            log.info("扫描指定包下，未发现符合条件的类", basePackages.toString());
            return;
        }
        log.info("扫描到符合条件的类：");
        candidates.forEach(item -> {
            log.info(item.getName());
        });

        for (Class<?> clazz : candidates) {
            String beanName = ClassUtils.getShortNameAsProperty(clazz);
            EntityModel root = EntityModel.of(clazz);
            buildChildEntityModel(root) ;
            EntityModelConstants.registerEntityModel(beanName, root);
        }

        log.info("=================扫描自定义注解结束======================");
    }

    private void buildChildEntityModel(EntityModel parentEntityModel) {
        Field[] fields = parentEntityModel.getEntityClass().getDeclaredFields() ;
        for(Field field : fields){
            Entity entity = field.getAnnotation(Entity.class);
            if (entity == null) {
                continue;
            }

            EntityModel childEntityModel = EntityModel.of(entity.entityClass());
            parentEntityModel.child(childEntityModel) ;

            buildChildEntityModel(childEntityModel);
        }
    }

    private List<Class<?>> scanPackages(String basePackages) {
        List<Class<?>> candidates = new ArrayList<Class<?>>();
        try {
            candidates.addAll(findCandidateClasses(basePackages));
        } catch (IOException e) {
            log.error("扫描指定包时出现异常", basePackages);
        }
        return candidates;
    }


    // 将指定包下面的符合条件的类返回
    private List<Class<?>> findCandidateClasses(String basePackage) throws IOException {
        List<Class<?>> candidates = new ArrayList<Class<?>>();
        // classpath*:com/scorpios/**/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                convertPath(basePackage) + '/' + this.DEFAULT_RESOURCE_PATTERN;
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        MetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory(resourceLoader);
        Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources(packageSearchPath);
        for (Resource resource : resources) {
            MetadataReader reader = readerFactory.getMetadataReader(resource);
            // 过滤哪些类符合条件，此处判断自定义注解 @Scorpios
            if (match(reader.getClassMetadata())) {
                Class<?> candidateClass = transform(reader.getClassMetadata().getClassName());
                if (candidateClass != null) {
                    candidates.add(candidateClass);
                    log.debug("扫描到符合要求的类：" + candidateClass.getName());
                }
            }
        }
        return candidates;
    }

    private String convertPath(String path) {
        return StringUtils.replace(path, ".", "/");
    }

    // 根据类名返回Class
    private Class<?> transform(String className) {
        Class<?> clazz = null;
        try {
            clazz = ClassUtils.forName(className, this.getClass().getClassLoader());
        } catch (ClassNotFoundException e) {
            log.info("未找到指定类", className);
        }
        return clazz;
    }


    private boolean match(ClassMetadata metadata) {
        Class<?> clazz = transformToClass(metadata.getClassName());
        return clazz != null && clazz.isAnnotationPresent(Entity.class);
    }

    private Class<?> transformToClass(String className) {
        Class<?> clazz = null;
        try {
            clazz = ClassUtils.forName(className, this.getClass().getClassLoader());
        } catch (ClassNotFoundException e) {
            log.info("未找到指定类", className);
        }
        return clazz;
    }

}
